package com.cw.utils.java.sm;


import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;

/**
 * 字段加密工具类
 * <p>
 * 支持对称加密算法 AES 的加密、解密
 * 本类涉及的byte编码均为UTF-8
 *
 * @author zengminghua
 */
public class SM4Algorithm {

    private static Logger logger = LoggerFactory.getLogger(SM4Algorithm.class);

    private static final BouncyCastleProvider BC = new BouncyCastleProvider();

    /**
     * 字段加密算法：SM4
     */
    private static final String ALGORITHM_SM4 = "SM4";

    /**
     * 密码器类型，算法/模式/补码方式
     */
    private static final String ALGORITHM_SM4_CBC_PKCS5 = "SM4/CBC/PKCS5Padding";

    /**
     * 默认秘钥种子，可更换，必须是16位。
     */
    public static volatile String REQPARAM_ENCRYPT_KEY = "044CB5LiL6L295bm";

    /**
     * 初始向量的方法, 全部为0
     * <p>
     *
     * @param algorithm
     * @return
     */
    private static byte[] initIv(String algorithm) {

        try {
            Cipher cipher = Cipher.getInstance(algorithm);
            int blockSize = cipher.getBlockSize();
            byte[] iv = new byte[blockSize];
            for (int i = 0; i < blockSize; ++i) {
                iv[i] = 0;
            }
            return iv;
        } catch (Exception e) {

            int blockSize = 16;
            byte[] iv = new byte[blockSize];
            for (int i = 0; i < blockSize; ++i) {
                iv[i] = 0;
            }
            return iv;
        }
    }

    /**
     * 初始向量的方法, 全部为0
     *
     * @param algorithm
     * @return
     */
    private static byte[] initBCIv(String algorithm) {

        try {
            Cipher cipher = Cipher.getInstance(algorithm, BC);
            int blockSize = cipher.getBlockSize();
            byte[] iv = new byte[blockSize];
            for (int i = 0; i < blockSize; ++i) {
                iv[i] = 0;
            }
            return iv;
        } catch (Exception e) {

            int blockSize = 16;
            byte[] iv = new byte[blockSize];
            for (int i = 0; i < blockSize; ++i) {
                iv[i] = 0;
            }
            return iv;
        }
    }

    /**
     * SM4加密
     *
     * @param content            待加密内容
     * @param reqParamEncryptKey 加密密钥
     * @return 密文（Base64 encode）
     */
    public static String sm4Encrypt(String content, String reqParamEncryptKey){

        try {
            // 创建密码器
            Cipher cipher = Cipher.getInstance(ALGORITHM_SM4_CBC_PKCS5, BC);//NOSONAR

            // 初始化向量值
            IvParameterSpec iv = new IvParameterSpec(initBCIv(ALGORITHM_SM4_CBC_PKCS5));//NOSONAR
            //Key sm4Key = new SecretKeySpec(Base64.decode(reqParamEncryptKey), ALGORITHM_SM4);
            Key sm4Key = new SecretKeySpec(reqParamEncryptKey.getBytes(), ALGORITHM_SM4);//NOSONAR
            // 使用密钥初始化，设置为 [加密模式] 的密码器
            cipher.init(Cipher.ENCRYPT_MODE, sm4Key, iv);

            // 加密
            byte[] result = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));

            // 通过Base64转码返回
            return Base64.encode(result);
        } catch (Exception e) {
           logger.error("加密出现异常：",e);
        }
        return "";
    }

    /**
     * SM4解密操作
     *
     * @param content            待解密内容
     * @param reqParamEncryptKey 解密密钥
     * @return 明文
     */
    public static String sm4Decrypt(String content, String reqParamEncryptKey){
        return sm4DecryptExpand("",content,reqParamEncryptKey);
    }


    /**
     * SM4解密操作
     *
     * @param content            待解密内容
     * @param reqParamEncryptKey 解密密钥
     * @return 明文
     */
    public static String sm4DecryptExpand(String name, String content, String reqParamEncryptKey){

        try {
            // 创建密码器
            Cipher cipher = Cipher.getInstance(ALGORITHM_SM4_CBC_PKCS5, BC);//NOSONAR

            // 初始化向量值
            IvParameterSpec iv = new IvParameterSpec(initBCIv(ALGORITHM_SM4_CBC_PKCS5));
            //Key sm4Key = new SecretKeySpec(Base64.decode(reqParamEncryptKey), ALGORITHM_SM4);
            Key sm4Key = new SecretKeySpec(reqParamEncryptKey.getBytes(), ALGORITHM_SM4);//NOSONAR
            // 使用密钥初始化，设置为 [解密模式] 的密码器
            cipher.init(Cipher.DECRYPT_MODE, sm4Key, iv);

            // 解密
            byte[] result = cipher.doFinal(Base64.decode(content));

            // 返回明文
            return new String(result, StandardCharsets.UTF_8);
        } catch (Exception e) {
            logger.error("====解密出现异常===propertyName={}，propertyValue={}",name,content);
            logger.error("====解密出现异常Exception===",e);
        }
        return "";
    }
}
